/******************************************************************************\
 *                                                                            *
 *                          Craftmesh Viewer                                  *
 *                   Flavio Bertini fl.bertini@gmail.com                      *
 *                                                                            *
 *                                                                            *
\******************************************************************************/


#if !defined(__Craftmesh_viewer_h__)
#define __Craftmesh_viewer_h__


#include <string>
#include <vector>
#include <GL/freeglut.h>
#include "Leap.h"
#include "Const.h"
#include "Craftmesh_model.h"
#include "Craftmesh_gengine.h"
#include "Craftmesh_controller.h"


using namespace Leap;
using namespace std;


void vew_display(void);                                    // display callback function
GLvoid vew_keyboard(unsigned char key, GLint x, GLint y);  // keyboard callback function

typedef enum {
  camera,
  object,
  edit,
  cut,
  boolean,
  sculpture
} APPMODE;

typedef enum {
  red_blue,
  red_cyan
} ANAGLYPHTYPE;

class Vew_GlutWindow
{

  public:
    const char*    title;         // window's title
    GLint          Id;            // window's id
    int            width;         // window's width
    int            height;        // window's height
    ANAGLYPHTYPE   anaglyphType;  // select anaglyph type (red/blue or red/cyan)
    bool           enaxes;        // enable/disable draw system's axes
    bool           engrid;        // enable/disable draw background grid
    bool           enSphere;      // enable/disable draw catching sphere mesh
    bool           enSolid;       // enable/disable draw solid mesh
    APPMODE        mode;          // select among camera, object, edit, boolean and sculpture mode
    bool           palmPlan;      // enable/disable palm reference
    bool           fingPos;       // enable/disable fingers reference
    bool           helpMenu;      // enable/disable draw application's menu
    bool           encyli;        // enable/disable vertical cylinder
    int            vmode;         // change the vision mode [mono, multiview, anaglyph]
    vector<string> menuCamera;    // application's menu in camera mode
    vector<string> menuObject;    // application's menu in object mode
    vector<string> menuEdit;      // application's menu in edit mode
    vector<string> menuCut;       // application's menu in cut mode
    vector<string> menuBoolean;   // application's menu in boolean mode
    vector<string> menuSculpture; // application's menu in sculpture mode
    bool           selecPlane;    // to activate the selection plane in edit mode
    bool           selecSphere;   // to activate the selection sphere in edit mode

    Vew_GlutWindow();
    ~Vew_GlutWindow();

    // initialize the window
    void vew_initWindow(int argc, char** argv);

    // draw text in 2D
    void vew_drawString2D(string text, int posx, int posy, const GLfloat* color);

    // draw application's menu
    void vew_drawMenu(int);

    // draw the background grids
    void vew_grid(int);

    // draw system's axes
    void vew_axes(int);

    // draw tip finger position
    void vew_drawFingersSphere(int);

    // draw palm position
    void vew_drawPalmPosition();

    // draw fingers position
    void vew_drawFingPosition(int);

    // draw mesh palm distance
    void vew_drawPalmMeshDistance(int, int, int);

    // draw selection sphere
    void vew_drawSelectionShpere(void);

    // draw selection sphere
    void vew_drawSelectionCutPlane(void);

}; // class GlutWindow


class Vew_GlutCamera
{
  public:
    // global view
    GLdouble lookAt[3];
    GLdouble lookTo[3];
    GLdouble lookUp[3];
    // front view
    GLdouble lookAtF[3];
    GLdouble lookToF[3];
    GLdouble lookUpF[3];
    // side view
    GLdouble lookAtS[3];
    GLdouble lookToS[3];
    GLdouble lookUpS[3];
    // top view
    GLdouble lookAtT[3];
    GLdouble lookToT[3];
    GLdouble lookUpT[3];
    // left eye view
    GLdouble lookAtLeft[3];
    GLdouble lookToLeft[3];
    // right eye view
    GLdouble lookAtRight[3];
    GLdouble lookToRight[3];
    // material solid mesh
    GLfloat mAmbient[4];
    GLfloat mDiffuse[4];
    GLfloat mSpecular[4];
    // material blue cyan and red
    GLfloat mBambient[4];
    GLfloat mBdiffuse[4];
    GLfloat mBspecular[4];
    GLfloat mCambient[4];
    GLfloat mCdiffuse[4];
    GLfloat mCspecular[4];
    GLfloat mRambient[4];
    GLfloat mRdiffuse[4];
    GLfloat mRspecular[4];
    GLfloat mShininess[1];
    // material selection sphere
    GLfloat mWambient[4];
    GLfloat mWdiffuse[4];
    GLfloat mWspecular[4];

    // left and right frustum
    float    leftLF, rightLF,
             bottomLF, topLF;
    float    leftRF, rightRF,
             bottomRF, topRF;
    float    fovAngle;         // field of view angle
    float    folDista;         // focal length
    float    zNear;            // near clipping plane
    float    zFar;             // far clipping plane
    float    zooming;
    float    eyeDelta;

    Vew_GlutCamera();
    ~Vew_GlutCamera();

    // reset camera zoom and position
    void vew_resetCamera(void);

    // zoom in/out
    void vew_zoomIn(float);
    void vew_zoomOut(float);
    void vew_applyZoom(bool zoomChange, float oldZoom);

    // create left and right eye
    void vew_createEyes(void);

    // Set the light and the matierial for the selection sphere
    void vew_setSphereMaterial(void);

    // Set the light and the matierial for solid mesh
    void vew_setLight(void);

    // set the light and the material for the eyes
    void vew_setRightLight(void);
    void vew_setLeftLight(void);

    // set the frustum view for the eyes
    void vew_setFrustumLeft(void);
    void vew_setFrustumRight(void);

    // set the view for the eyes
    void vew_setLeftEye(void);
    void vew_setRightEye(void);

}; // class GlutCamera


// hand texture
typedef struct
{
  vector<GLubyte*> handImage;
  vector<GLuint> texHandImage;
  GLint wHandImage, hHandImage, cHandImage;
} Vew_HandTexture;


// image struct
typedef struct _ImageRec {
  GLushort imagic;
  GLushort type;
  GLushort dim;
  GLushort xsize, ysize, zsize;
  GLuint min, max;
  GLuint wasteBytes;
  GLbyte name[80];
  unsigned long colorMap;
  FILE *file;
  GLubyte *tmp, *tmpR, *tmpG, *tmpB;
  unsigned long rleEnd;
  GLuint *rowStart;
  GLint *rowSize;
} Vew_ImageRec;


Vew_ImageRec *vew_ImageOpen(const char *fileName);                          // open image
unsigned* vew_rgbLoader(const char *name, GLint *width, GLint *height,      // load rgb image
                        GLint *components, GLbyte modAlpha);
void vew_ImageClose(Vew_ImageRec *image);                                   // close image
void vew_ImageGetRow(Vew_ImageRec *image, GLubyte *buf,                     // load a row
                     GLint y, GLint z);
void vew_bwtorgba(GLubyte *b,GLubyte *l,GLint n);                           // conversion stuff
void vew_latorgba(GLubyte *b, GLubyte *a,GLubyte *l,GLint n);
void vew_rgbtorgba(GLubyte *r,GLubyte *g,GLubyte *b,
                   GLubyte *l,GLint n,GLbyte modAlpha);
void vew_rgbatorgba(GLubyte *r,GLubyte *g,GLubyte *b,
                    GLubyte *a,GLubyte *l,GLint n);
void vew_ConvertShort(GLushort *array, long length);
void vew_ConvertLong(unsigned *array, long length);

#endif // __Craftmesh_viewer_h__
